package com.aiwiown.snackmq.network.handler;

import com.aiwiown.snackmq.common.message.Message;
import com.aiwiown.snackmq.common.message.MessageType;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

/**
 * 心跳处理器，用于处理客户端和服务端的心跳交互
 * 该处理器继承自Netty的SimpleChannelInboundHandler，专注于处理入站消息
 *
 * @param <Message> 处理的消息类型
 */
@Slf4j
public class HeartbeatHandler extends SimpleChannelInboundHandler<Message> {

    // 标记当前处理器是客户端还是服务端
    private final boolean isClient;

    /**
     * 构造函数，初始化HeartbeatHandler
     *
     * @param isClient 表示当前处理器是否为客户端处理器
     */
    public HeartbeatHandler(boolean isClient) {
        this.isClient = isClient;
    }

    /**
     * 处理入站消息
     * 如果消息类型为心跳，则直接消费该消息，不再向后传递
     * 否则，将消息传递给下一个处理器
     *
     * @param ctx 上下文，包含通道信息
     * @param msg 入站消息
     * @throws Exception 可能抛出的异常
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
        if (msg.getType() == MessageType.HEARTBEAT) {
            if (!isClient) { // 仅服务端会收到心跳
                log.debug("Server received and handled heartbeat from {}", ctx.channel().remoteAddress());
            }
            // 消费心跳消息，不再向后传递
            return;
        }
        // 将非心跳的业务消息传递给下一个处理器
        ctx.fireChannelRead(msg);
    }

    /**
     * 处理用户事件
     * 当检测到空闲状态时，根据客户端或服务端的不同角色，执行不同的操作
     *
     * @param ctx 上下文，包含通道信息
     * @param evt 用户事件
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            // 客户端在“写”空闲时，主动发送心跳
            if (event.state() == IdleState.WRITER_IDLE && isClient) {
                log.debug("Client writer idle, sending heartbeat to: {}", ctx.channel().remoteAddress());
                ctx.writeAndFlush(createHeartbeatMessage());
            }
            // 服务端在“读”空闲时，认为客户端已失联，主动关闭连接
            else if (event.state() == IdleState.READER_IDLE && !isClient) {
                log.warn("Server reader idle, no data received from client for a while, closing connection: {}", ctx.channel().remoteAddress());
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    /**
     * 创建心跳消息
     * 该方法构建并返回一个心跳类型的消息
     *
     * @return 心跳消息实例
     */
    private Message createHeartbeatMessage() {
        return Message.builder()
                .type(MessageType.HEARTBEAT)
                .build();
    }

    /**
     * 处理异常
     * 记录错误日志，并将异常传递给下一个处理器
     *
     * @param ctx 上下文，包含通道信息
     * @param cause 异常原因
     * @throws Exception 可能抛出的异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("Exception in HeartbeatHandler for {}", ctx.channel().remoteAddress(), cause);
        // 将异常传递给下一个处理器，让统一的异常处理逻辑来决定是否关闭连接
        ctx.fireExceptionCaught(cause);
    }
}
